#pragma once

#include <cstddef>
#include <utility>

/**
 * @brief 第八版本：实现移动语义，禁止拷贝。
 *
 * 核心点：
 *   - 删除拷贝构造 / 拷贝赋值以保持“独占所有权”。
 *   - 移动构造：接管资源并将源置空。
 *   - 移动赋值：先释放自身资源，再接管对方资源。
 */
template <typename T, typename Deleter = void(*)(T*)>
class UniquePtr {
public:
    using pointer      = T*;
    using element_type = T;
    using deleter_type = Deleter;

    static void default_delete(T* ptr) noexcept {
        delete ptr;
    }

    constexpr UniquePtr() noexcept
        : ptr_(nullptr)
        , deleter_(default_delete) {}

    constexpr UniquePtr(std::nullptr_t) noexcept
        : UniquePtr() {}

    explicit UniquePtr(pointer ptr) noexcept
        : ptr_(ptr)
        , deleter_(default_delete) {}

    /**
     * @brief 自定义删除器的构造。
     *
     * @param ptr     需要托管的裸指针。
     * @param deleter 删除器，函数指针或兼容类型。
     */
    UniquePtr(pointer ptr, deleter_type deleter) noexcept
        : ptr_(ptr)
        , deleter_(std::move(deleter)) {}

    /// 禁用拷贝构造，防止多个智能指针共享同一资源
    UniquePtr(const UniquePtr&)            = delete;
    /// 禁用拷贝赋值，同上
    UniquePtr& operator=(const UniquePtr&) = delete;

    /**
     * @brief 移动构造函数。
     *
     * 接管 other 的资源，并将 other 的指针置空。
     */
    UniquePtr(UniquePtr&& other) noexcept
        : ptr_(other.ptr_)
        , deleter_(std::move(other.deleter_)) {
        other.ptr_ = nullptr;
    }

    /**
     * @brief 移动赋值运算符。
     *
     * 先释放当前托管的资源，再接管 other 的资源，并将 other 置空。
     */
    UniquePtr& operator=(UniquePtr&& other) noexcept {
        if (this != &other) {       // 防止自我移动赋值
            reset();                // 释放自身已有资源
            ptr_     = other.ptr_;  // 接管指针
            deleter_ = std::move(other.deleter_);
            other.ptr_ = nullptr;   // 源对象置空
        }
        return *this;
    }

    ~UniquePtr() {
        reset();
    }

    void swap(UniquePtr& other) noexcept {
        std::swap(ptr_, other.ptr_);
        std::swap(deleter_, other.deleter_);
    }

    void reset(pointer ptr = nullptr) noexcept {
        if (ptr_) {
            deleter_(ptr_);
        }
        ptr_ = ptr;
    }

    pointer release() noexcept {
        pointer raw = ptr_;
        ptr_ = nullptr;
        return raw;
    }

    pointer get() const noexcept {
        return ptr_;
    }

    element_type& operator*() const noexcept {
        return *ptr_;
    }

    pointer operator->() const noexcept {
        return ptr_;
    }

    explicit operator bool() const noexcept {
        return ptr_ != nullptr;
    }

private:
    pointer      ptr_{nullptr};            ///< 当前托管的裸指针
    deleter_type deleter_{default_delete}; ///< 删除器对象
};

template <typename T, typename Deleter>
void swap(UniquePtr<T, Deleter>& lhs, UniquePtr<T, Deleter>& rhs) noexcept {
    lhs.swap(rhs);
}